import QtQuick 2.0
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import "qrc:///MyControls"

Item {
    id:item
    property int mineCnt: 10
    property int mineMapWidth: 9
    property int mineMapHeight: 9

    readonly property int notOpen: 0
    readonly property int opened: 1
    readonly property int flaged: 2
    readonly property int boomed: 3
    readonly property int unknown: 4

    //状态
    property bool inGame: false
    property int mineOkCnt: 0
    property int flagCnt: 0
    property int openCnt: 0

    signal gameOver(bool success);

    //GridView 宽高保持
    onHeightChanged:{
        console.log(item.height)
        parentResize();
    }
    onWidthChanged: {
        console.log(item.width)
        parentResize();
    }
    //kuangao
    property real itemRatio: mineMapWidth/mineMapHeight
    function parentResize(){
        var ratio = item.width / item.height;
        if(ratio > itemRatio){
            gridViewMine.height = item.height
            gridViewMine.width = gridViewMine.height * itemRatio
        }else{
            gridViewMine.width = item.width
            gridViewMine.height = gridViewMine.width / itemRatio
        }
    }

    GridView{
        id:gridViewMine
        anchors.centerIn: parent
        model: modelMine

        cellWidth: gridViewMine.width / mineMapWidth
        cellHeight: gridViewMine.height / mineMapHeight
        delegate: MineCell{
                width: gridViewMine.cellWidth
                height: gridViewMine.cellHeight

                onLeftClicked: {
                    if(!inGame){
                        endGame(isSuccess());
                        return ;
                    }

                    //首次打开
                    if(0 === openCnt){
                        createMine(no);
                        calculNearMineCnt();
                    }

                    console.log("clicked: row:" + row + "," + col + " index:" + no + " mineState:" + mineState);
                    openCell(row,col);

                    if(isSuccess())
                        endGame(true);
                }
                onRightClicked: {
                    if(!inGame){
                        endGame(isSuccess());
                        return ;
                    }

                    if(notOpen == mineState){
                        mineState = flaged;
                        flagCnt++;
                        if(isMine(mineData))
                            mineOkCnt++;
                    }
                    else if(flaged == mineState){
                        mineState = unknown;
                        flagCnt--;
                        if(isMine(mineData))
                            mineOkCnt--;
                    }
                    else if(unknown == mineState){
                        mineState = notOpen;
                    }

                    if(isSuccess())
                        endGame(true);
                }

        }
    }

    ListModel{
        id:modelMine
    }

    Component.onCompleted: {
        startGame();
    }

    function startGame(){
        inGame = true;
        mineOkCnt = 0;
        flagCnt = 0;
        openCnt = 0;

        resetMineMap(mineMapWidth,mineMapHeight);
    }

    function endGame(success){
        inGame = false;

        if(false === success)
            openAllNotOpenMine();

        gameOver(success); //信号
    }

    function openAllNotOpenMine(){
        for(var i = 0; i < mineMapWidth*mineMapHeight; i++){
            if(notOpen === modelMine.get(i).mineState)
                modelMine.setProperty(i,"mineState",opened);
        }
    }

    function resetMineMap(){
        modelMine.clear();
        for(var i = 0; i < mineMapWidth*mineMapHeight; i++){
            modelMine.append({   no:i,
                                 row:Math.floor(i / mineMapWidth),
                                 col:i%mineMapWidth,
                                 mineState:notOpen,
                                 mineData:0
                             });
        }
    }

    //生成mine 可指定一个位置不为地雷 防止初次点击游戏结束
    function createMine(cantIndex){
        //雷数大数=格子数-1
        if(mineCnt >= (modelMine.count - 1))
            mineCnt = modelMine.count - 1;

        console.log(cantIndex + ":不能为雷");

        //记录不能生成地雷的位置 防止随机数重复 首次点击的位置也不能是地雷
        var cantMineIndexs = [];
        if(cantIndex >= 0 && cantIndex < modelMine.count){
            cantMineIndexs.push(cantIndex);
            console.log(cantIndex + ":不能为雷");
        }

        console.log("can not mine index:" + cantMineIndexs);
        for(var cnt = 0; cnt < mineCnt; cnt++){
            //随机选定一个位置 但不能是cantMineIndexs中的位置
            var index;
            do{
                //Math.random()生成一个[0,1)之间的小数  Math.floor()对小数向下取整
                index = Math.floor(Math.random()*(modelMine.count));
            }while(-1 !== cantMineIndexs.indexOf(index));
            cantMineIndexs.push(index);
            modelMine.setProperty(index,"mineData",-1);
        }
    }

    function calculNearMineCnt(){
        for(var index = 0; index < modelMine.count; index++)
        {
            //是地雷就将周围的8个格子不是地雷的格子雷数加1
            if(isMine(modelMine.get(index).mineData))
            {
                //转二维位置
                var row = Math.floor(index / mineMapWidth);
                var col = index % mineMapWidth;

                //遍历周围8个格子
                var offsetRow,offsetCol;
                for(offsetRow=-1;offsetRow<2;offsetRow++)
                {
                    for(offsetCol=-1;offsetCol<2;offsetCol++)
                    {
                        var nearRow = row + offsetRow;
                        var nearCol = col + offsetCol;

                        if(isInMap(nearRow,nearCol))
                        {
                            var currentIndex = nearRow * mineMapWidth + nearCol;
                            var mineData = modelMine.get(currentIndex).mineData;
                            if(false === isMine(mineData)){
                                mineData++;
                                modelMine.setProperty(currentIndex,"mineData",mineData);
                            }
                        }
                    }
                }
            }
        }
    }

    function openCell(row,col){
        var currentIndex = row * mineMapWidth + col;
        var mineState = modelMine.get(currentIndex).mineState;

        if(notOpen === mineState)
        {
            modelMine.setProperty(currentIndex,"mineState",opened);
            openCnt++;

            if(isMine(modelMine.get(currentIndex).mineData)){
                modelMine.setProperty(currentIndex,"mineState",boomed);
                endGame(false);
                return ;
            }

            //该格子周围0个雷 打开附近的8个格子 八近邻中有0则会递归
            if(0 === modelMine.get(currentIndex).mineData){
                var offsetRow,offsetCol;
                for(offsetRow=-1; offsetRow<2; offsetRow++)
                {
                    for(offsetCol=-1; offsetCol<2; offsetCol++)
                    {
                        var nearRow = row + offsetRow;
                        var nearCol = col + offsetCol;
                        if(isInMap(nearRow,nearCol)){
                            currentIndex = nearRow * mineMapWidth + nearCol;
                            openCell(nearRow,nearCol);
                        }
                    }
                }
            }
        }
    }

    function isInMap(row,col){
        return (row >= 0 && row < mineMapHeight) && (col >= 0 && col < mineMapWidth);
    }

    function isSuccess(){
        //不为mine的都需打开
        if(openCnt === (modelMine.count - mineCnt)){
            return true;
        }

        //为mine的都需插旗
        if(mineOkCnt === mineCnt && flagCnt === mineCnt){
            return true;
        }

        return false;
    }

    function isMine(mineData){
        return mineData < 0;
    }

    function setLevel(level){
        if(0 === level){
            mineCnt = 10;
            mineMapWidth = 9;
            mineMapHeight = 9;
        }else if(1 === level){
            mineCnt = 40;
            mineMapWidth = 16;
            mineMapHeight = 16;
        }else if(2 === level){
            mineCnt = 99;
            mineMapWidth = 30;
            mineMapHeight = 16;
        }

        parentResize();
        startGame();
    }
}
